home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
THINKC
/
4_0
/
GREPSTUF
/
GREPIO.C
< prev
next >
Wrap
Text File
|
1986-10-31
|
10KB
|
507 lines
/*
GrepIO - routines for treating TEXT or WORD (MacWrite)
files as a stream of characters or lines, and for output file
setup and termination.
*/
# include <FileMgr.h>
# include <StdFilePkg.h>
# include "Grep.h"
# define bufSize 1024 /* input buffer size */
# define lineLen 65 /* output line len before break */
typedef Byte ByteBuf[];
typedef struct
{
int version;
int paraOffset;
int paraCount;
} DocInfo3;
typedef struct
{
int paraType;
int paraLen;
} ParaInfo3;
typedef struct
{
long iArrayPos;
int iArrayLen;
} DocInfo6;
typedef struct /* information array element */
{
int height;
int pagePos;
long **paraHand;
union
{
Byte st; /* first byte is status */
long pos;
} stPos;
int dataLength;
int formats;
} ParaInfo6, InfoArray[];
SFReply outReply; /* output file */
SFReply theStream; /* SFGetFile reply record */
Boolean streamOpen = false; /* whether stream currently open */
int streamType; /* file type of stream */
int f; /* input file reference number */
/* vars needed for TEXT stream only */
char filBuf[bufSize]; /* file buffer */
long fLen;
int fChars;
/* vars needed for WORD stream only */
ByteBuf **paraBuf = nil;
InfoArray **infoHand = nil;
Boolean compressed;
Boolean inPara;
int nParas; /* number of paragraphs */
int paraNum; /* current paragraph number */
int pIndex; /* index into paragraph */
int pChars; /* number of chars extracted from paragraph */
int pLen; /* number of chars in paragraph */
/* decompression variables */
Boolean firstHalf; /* which half of current index char */
Boolean needNib; /* true = 2nd nibble needed for ascii */
Boolean nextAsc; /* true = two nibbles needed */
Byte lastNib; /* holds last nibble */
/* miscellaneous */
Point dlogWhere = { 70 /* = y */, 100 /* = x */ };
OSType type[2] = { 'WORD', 'TEXT' };
MyFRead (p, amount)
Ptr p;
long amount;
{
(void) FSRead (f, &amount, p);
}
MyFSeek (pos)
long pos;
{
(void) SetFPos (f, fsFromStart, pos);
}
/*
_FSOpen - like FSOpen, but has open mode parameter.
CloseStream - close current stream, if one is open. Releases any
heap storage currently used, if stream is WORD type.
OpenStream - open 'TEXT' or 'WORD' stream.
Return noErr if file opened OK, fnOpnErr or mFulErr if not.
if OK, set fileOpen true.
*/
OSErr _FSOpen (fName, vRefNum, refNum, mode)
StringPtr fName;
int vRefNum;
int *refNum;
int mode;
{
ParamBlockRec p;
register OSErr result;
p.ioParam.ioNamePtr = fName;
p.ioParam.ioVRefNum = vRefNum;
p.ioParam.ioPermssn = mode;
p.ioParam.ioVersNum = 0;
p.ioParam.ioMisc = 0;
result = PBOpen (&p, false);
*refNum = p.ioParam.ioRefNum;
return (result);
}
CloseStream ()
{
if (streamOpen)
{
(void) FSClose (f);
/*(void) FlushVol (nil, theStream.vRefNum);*/
streamOpen = false;
if (paraBuf != nil)
{
DisposHandle (paraBuf);
paraBuf = nil;
}
if (infoHand != nil)
{
DisposHandle (infoHand);
infoHand = nil;
}
}
}
OSErr OpenStream ()
{
DocInfo3 docInfo3;
DocInfo6 docInfo6;
register OSErr result = fnOpnErr;
register int curRes;
CloseStream (); /* close any currently open stream */
curRes = CurResFile ();
UseResFile (0);
SFGetFile (dlogWhere, "\p", nil, 2, &type, nil, &theStream);
UseResFile (curRes);
Update (); /* refresh screen immediately */
if (theStream.good)
{
if (_FSOpen (theStream.fName, theStream.vRefNum,
&f, fsRdPerm) == noErr)
{
streamOpen = true;
result = noErr;
}
}
if (result == noErr) /* so far, so good */
{
if (theStream.fType == 'TEXT')
{
streamType = text;
fChars = 0; /* set these to trigger a read on the first */
fLen = 0; /* call to StreamGetC() */
}
else /* must be WORD file - determine version */
{
paraBuf = (ByteBuf **) NewHandle (0L);
MyFRead (&docInfo3, (long) sizeof (DocInfo3));
if (docInfo3.version == 3) /* MacWrite 2.2 file */
{
streamType = mwrt3;
nParas = docInfo3.paraCount;
MyFSeek ((long) docInfo3.paraOffset);
}
else if (docInfo3.version == 6) /* MacWrite 4.5 file */
{
streamType = mwrt6;
MyFSeek (264L); /* 252 + 12 */
MyFRead (&docInfo6, (long) sizeof (DocInfo6));
MyFSeek (docInfo6.iArrayPos);
infoHand = (InfoArray **) NewHandle (docInfo6.iArrayLen);
if (infoHand == nil)
{
CloseStream ();
result = mFulErr;
}
else
{
HLock (infoHand);
MyFRead (*infoHand, (long) docInfo6.iArrayLen);
HUnlock (infoHand);
nParas = docInfo6.iArrayLen / sizeof (ParaInfo6);
}
}
else
{
CloseStream ();
Alarm ("\pFile created by unsupported MacWrite version");
result = fnOpnErr;
}
paraNum = -1;
inPara = false; /* not in any paragraph yet */
}
}
return (result);
}
Boolean GetStream ()
{
if (OpenStream () != noErr)
return (false);
DisplayString (theStream.fName);
DisplayString ("\p (");
DisplayString (streamType == text ? "\pText" : "\pMacWrite");
DisplayString ("\p file)\r");
return (true);
}
/*
_Decompress takes a nibble at a time of compressed text. If more
nibbles are needed to complete the next character, return -1, else
returns the character.
*/
_Decompress (b)
Byte b;
{
register int result = -1;
if (needNib) /* Low half of ascii nibble is needed. */
{
needNib = false;
result = lastNib | b; /* Put the two halves together */
}
else if (nextAsc) /* Two nibbles are needed */
{
nextAsc = false;
lastNib = b << 4; /* Save this one as the high nibble */
needNib = true; /* Need one more nibble */
}
else if (b == 15) /* Nibble of 15 means the next char is ascii */
nextAsc = true;
else /* Add the nibble value to the English decompression */
/* key (saved as Resource Type 'STR ' 700 in file) */
/* to get the proper character */
{
result = " etnroaisdlhcfp" [b]; /* note: C string */
}
return (result);
}
Boolean ReadParaBuf ()
{
SetHandleSize (paraBuf, pLen); /* make big enough */
if (MemError () != noErr)
{
Alarm ("\pCan't read paragraph buffer");
paraNum = nParas; /* force stream close and exit of GetC loop */
return (false);
}
HLock (paraBuf);
MyFRead (*paraBuf, (long) pLen);
HUnlock (paraBuf);
return (true);
}
WordStreamGetC () /* return -1 on EOF */
{
register int c;
register int result;
ParaInfo3 paraInfo3;
if (!inPara) /* must read in next paragraph */
{
for (;;)
{
if (++paraNum >= nParas)
{
CloseStream ();
return (-1);
}
if (streamType == mwrt3)
{
MyFRead (¶Info3, (long) sizeof (ParaInfo3));
pLen = paraInfo3.paraLen;
if (ReadParaBuf () == false)
continue;
if (paraInfo3.paraType != 1)
{
continue; /* not text */
}
/* adding two skips length word */
if ((pLen = ((int *) **paraBuf)[0] + 2) == 2)
continue; /* empty paragraph */
pChars = 2;
compressed = false;
inPara = true;
break;
}
else /* mwrt6 */
{
if ((**infoHand)[paraNum].height <= 0)
{
continue; /* not text */
}
/*
Seek to this paragraph's data (must mask the high byte to get the
correct value). Move to the paragraph, get its length, make
the pointer big enough, and read it in. (skip to next para if this
one is empty, though.)
compressed will be set true if the paragraph is compressed.
*/
MyFSeek ((**infoHand)[paraNum].stPos.pos & 0x00FFFFFF);
MyFRead (&pLen, (long) sizeof (int)); /* get length */
if (pLen == 0)
{
continue; /* empty para - skip */
}
if (ReadParaBuf () == false)
continue;
compressed = ((**infoHand)[paraNum].stPos.st >> 3) & 1;
inPara = true;
nextAsc = false;
needNib = false;
pIndex = 0; /* index into current paragraph */
pChars = 0; /* chars extracted from current paragraph */
firstHalf = true; /* use first half of current index char */
break;
}
}
}
/*
At this point, know either that we have a new non-empty paragraph, or
are still in the previous one.
*/
if (!compressed) /* uncompressed */
{
c = (**paraBuf)[pChars];
}
else
{
do
{
c = (**paraBuf)[pIndex];
if (firstHalf)
{
c = _Decompress (((Byte) c) >> 4);
}
else
{
c = _Decompress ((Byte) (c & 0x0f));
++pIndex; /* go to next char at next index */
}
firstHalf = !firstHalf;
} while (c == -1);
}
if (++pChars >= pLen) /* see if need new paragraph next time */
inPara = false;
return (c);
}
/*
StreamGetC - get character from stream.
*/
StreamGetC ()
{
if (!streamOpen)
return (-1);
if (streamType != text)
return (WordStreamGetC ());
if (fChars >= fLen) /* need to read in a new block */
{
fLen = bufSize;
(void) FSRead (f, &fLen, filBuf);
if (fLen == 0)
{
CloseStream ();
return (-1);
}
fChars = 0;
}
return (filBuf[fChars++]);
}
/*
StreamGetS - get string from stream.
Returns nil if no string obtained, otherwise a pointer to the argument.
*/
StringPtr StreamGetS (s)
register StringPtr s;
{
register int c;
register StringPtr result = nil;
s[0] = 0; /* clear string */
while ((c = StreamGetC ()) != -1)
{
result = s; /* got something, so StreamGetS succeeds */
if (c == '\r' || (s[0] > lineLen && c == ' '))
break;
s[++s[0]] = c; /* add char to end */
}
return (result);
}
FileOutput ()
{
FInfo f;
long pos;
register int curRes;
if (fileOpen) /* close it */
{
fileOpen = false;
(void) GetFPos (outFile, &pos);
(void) SetEOF (outFile, pos);
(void) FSClose (outFile);
(void) FlushVol (nil, outReply.vRefNum);
SetItem (theMenu, saveOutput, "\pSave Output...");
}
else
{
curRes = CurResFile ();
UseResFile (0);
SFPutFile (dlogWhere, "\pWrite To...", "\p", nil, &outReply);
UseResFile (curRes);
Update (); /* refresh screen immediately */
if (outReply.good)
{
if (GetFInfo (outReply.fName, outReply.vRefNum, &f) == noErr) /* exists */
{
if (f.fdType != 'TEXT')
{
Alarm ("\pNot a TEXT File");
return;
}
}
else /* doesn't exist. create it. */
{
if (Create (outReply.fName, outReply.vRefNum,
'Grep', 'TEXT') != noErr)
{
Alarm ("\pCan't Create");
return;
}
}
if (_FSOpen (outReply.fName, outReply.vRefNum,
&outFile, fsWrPerm) != noErr)
Alarm ("\pCan't Open");
else
{
fileOpen = true;
SetItem (theMenu, saveOutput, "\pStop Saving Output");
}
}
}
}